/*
 * MIT License
 *
 * Copyright (c) 2025 Mark·虎
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

package com.hsxxherp.key.common.util;

import com.hsxxherp.key.common.error.ErrorCode;
import com.hsxxherp.key.common.exception.BusinessException;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;

/**
 * PasswordUtil 工具类，用于密码加密、验证和重置
 *
 * @author Mark·虎克 (2486970363@qq.com)
 */
public class PasswordUtil {

    private static final String ALGORITHM_NAME = "SM4";
    private static final String ALGORITHM_VERSION = "1.0";
    private static final int SALT_LENGTH = 16;

    private PasswordUtil() {
        // 私有构造函数，防止实例化
    }

    /**
     * 加密密码
     *
     * @param password 明文密码
     * @return 包含算法名称、版本、盐值和加密后密码的字符串
     */
    public static String encryptPassword(String password) {
        try {
            // 生成盐值
            byte[] salt = generateSalt();
            // 生成密钥
            byte[] key = generateKey();
            // 生成初始化向量（仅用于CBC模式）
            byte[] iv = generateIV();

            // 将盐值和密码拼接
            String passwordWithSalt = new String(salt, StandardCharsets.UTF_8) + password;
            byte[] plaintext = passwordWithSalt.getBytes(StandardCharsets.UTF_8);

            // 使用 SM4 CBC 模式加密
            String encryptedPassword = SM4Util.encryptCBC(plaintext, key, iv);

            // 构建包含算法名称、版本、盐值和加密后密码的字符串
            return String.format("%s:%s:%s:%s", ALGORITHM_NAME, ALGORITHM_VERSION, Base64.getEncoder().encodeToString(salt), encryptedPassword);
        } catch (Exception e) {
            throw new BusinessException("密码加密失败", e).setCode(ErrorCode.CODE_100031);
        }
    }

    /**
     * 验证密码
     *
     * @param rawPassword       明文密码
     * @param encryptedPassword 加密后的密码字符串
     * @return 密码是否匹配
     */
    public static boolean verifyPassword(String rawPassword, String encryptedPassword) {
        try {
            // 解析加密后的密码字符串
            String[] parts = encryptedPassword.split(":");
            if (parts.length != 4) {
                return false;
            }
            String algorithmName = parts[0];
            String algorithmVersion = parts[1];
            byte[] salt = Base64.getDecoder().decode(parts[2]);
            String encrypted = parts[3];

            // 检查算法名称和版本
            if (!ALGORITHM_NAME.equals(algorithmName) || !ALGORITHM_VERSION.equals(algorithmVersion)) {
                return false;
            }

            // 生成密钥和初始化向量
            byte[] key = generateKey();
            byte[] iv = generateIV();

            // 将盐值和明文密码拼接
            String passwordWithSalt = new String(salt, StandardCharsets.UTF_8) + rawPassword;
            byte[] plaintext = passwordWithSalt.getBytes(StandardCharsets.UTF_8);

            // 重新加密明文密码
            String reEncryptedPassword = SM4Util.encryptCBC(plaintext, key, iv);

            // 比较重新加密的密码和原加密密码
            return encrypted.equals(reEncryptedPassword);
        } catch (Exception e) {
            throw new BusinessException("密码验证失败", e).setCode(ErrorCode.CODE_100032);
        }
    }

    /**
     * 重置密码
     *
     * @param oldEncryptedPassword 旧的加密密码
     * @param newPassword          新的明文密码
     * @return 新的加密密码字符串
     */
    public static String resetPassword(String newPassword, String oldEncryptedPassword, String encryptedPassword) {
        if (oldEncryptedPassword == null && verifyPassword(oldEncryptedPassword, encryptedPassword)) {
            throw new BusinessException("密码重置失败").setCode(ErrorCode.CODE_100033);
        }
        // 这里可以添加一些额外的验证逻辑，如旧密码是否正确等
        return encryptPassword(newPassword);
    }

    /**
     * 生成盐值
     *
     * @return 盐值字节数组
     */
    private static byte[] generateSalt() {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[SALT_LENGTH];
        random.nextBytes(salt);
        return salt;
    }

    /**
     * 生成密钥
     *
     * @return 密钥字节数组
     */
    private static byte[] generateKey() {
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 16);
        return uuid.getBytes(StandardCharsets.UTF_8);
    }

    /**
     * 生成初始化向量
     *
     * @return 初始化向量字节数组
     */
    private static byte[] generateIV() {
        SecureRandom random = new SecureRandom();
        byte[] iv = new byte[16];
        random.nextBytes(iv);
        return iv;
    }
}